package vh.android.multiconnector.library;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import vh.android.multiconnector.library.model.ClientListener;
import android.content.Intent;
import android.util.Log;

public class Client implements Runnable, ClientListener {

	private static final String LOG_TAG = Client.class.getName();
	public static final String IA_PING = ConnectionHandler.CHANNEL_ACTION
			+ "_PING";
	private static final int TIMEOUT = 10000;
	private boolean mRunning;
	private Thread mThread;
	private int mPort;
	private String mIP;
	private Socket mClient;
	private ArrayList<String> mQueue = new ArrayList<String>();
	private String mID;

	/**
	 * ID can be anything to identify this connection
	 */
	public Client(String pID, String pIP, int pPort) {
		this.mID = pID;
		this.mIP = pIP;
		this.mPort = pPort;
	}

	private void joinServer() {
		try {
			InetAddress serverAddr = InetAddress.getByName(mIP);
			mClient = new Socket(serverAddr, mPort);
			mClient.setSoTimeout(TIMEOUT);
			ConnectionHandler conection = new ConnectionHandler(mID, this,
					mClient);
			conection.start();
		} catch (UnknownHostException e) {
			// TODO
			e.printStackTrace();
		} catch (IOException e) {
			// TODO
			e.printStackTrace();
		}
	}

	/**
	 * Send messages to any port you want to.
	 * 
	 * @param pIntent
	 * @param pPort
	 */
	public void send(Intent pIntent) {
		if (pIntent == null)
			return;
		if (!pIntent.getAction().startsWith(ConnectionHandler.CHANNEL_ACTION)) {
			Log.e(LOG_TAG, "Illegal action for intent. Intent cannot be send.");
			return;
		}
		pIntent.setAction(pIntent.getAction());
		send(pIntent.toUri(0));
	}

	@Override
	public void run() {
		// try to join server
		joinServer();

		if (mClient == null) {
			Log.e(LOG_TAG, "Couldnt connect to server");
			return;
		}

		// send ping each 5s
		new Timer().schedule(new TimerTask() {

			@Override
			public void run() {
				System.out.println("SEND HEARTBEAT");
				send(new Intent(IA_PING));
			}
		}, 0L, 5000L);

		// TODO use !Thread.currentThread().isInterrupted() instead of running
		while (mRunning) {
			try {
				String message = null;
				synchronized (mQueue) {
					if (mQueue.size() == 0)
						continue;
					message = mQueue.remove(0);
				}
				// send message
				PrintWriter out = new PrintWriter(new BufferedWriter(
						new OutputStreamWriter(mClient.getOutputStream())),
						true);
				out.println(message);
			} catch (Exception e) {
			}
		}
	}

	private void send(String pMessage) {
		synchronized (mQueue) {
			mQueue.add(pMessage);
		}
	}

	/**
	 * whether service is running
	 * 
	 * @return
	 */
	public boolean isRunning() {
		return mRunning;
	}

	/**
	 * start unless already running
	 */
	public void start() {
		if (!mRunning) {
			mRunning = true;
			mThread = new Thread(this);
			mThread.start();
		}
	}

	public void stop() {
		mRunning = false;
	}

	@Override
	public void onServerJoined(String pID) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onServerLeft(String pID) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onServerTimedout(String pID) {
		Log.e(LOG_TAG, "Server timedout");
	}

	@Override
	public void onServerMessageReceived(String pID, Intent pData) {
		// TODO Auto-generated method stub

	}
}
